//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.1.1
#include "rtc_bsp.h"

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

/*RTC总管理结构体*/
static struct
{
	void (*Over_Callback)(void);
    void (*Alarm_Callback)(void);
    void (*Sec_Callback)(void);
}RTC_Data = { NULL };


/*RTC中断优先级配置*/
static void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	/* 嵌套向量中断控制器组选择 */
	//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

	/* 配置中断源 */
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
	/* 抢断优先级*/
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	/* 子优先级 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	/* 使能中断 */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	/* 初始化配置NVIC */
	NVIC_Init(&NVIC_InitStructure);
}
/*RTC配置*/
static void WHT_RTC_BSP_Config(const WHT_RTC_Config_t* config)
{
	if (config->Clock_Source == NO_Clk)
		return;
	
	RTC_Data.Over_Callback = config->Over_Interrupt == ENABLE ? config->Over_Callback : NULL;
	RTC_Data.Alarm_Callback = config->Alarm_Interrupt == ENABLE ? config->Alarm_Callback : NULL;
	RTC_Data.Sec_Callback = config->Sec_Interrupt == ENABLE ? config->Sec_Callback : NULL;

	if ((config->Alarm_Interrupt == ENABLE) || (config->Over_Interrupt == ENABLE) || (config->Sec_Interrupt == ENABLE))
	NVIC_Configuration();
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//open PWR BKP clock
	PWR_BackupAccessCmd(ENABLE);                                            //open RTC & BKP registers write mode
	BKP_DeInit();                                                           //reset all BKP registers data 会将备份数据也给复位的
	if (config->Clock_Source == LSE_OSC_32768Hz)
	{
		unsigned int count_over = 36000000;//for 72MHZ wait > 1sec
		RCC_LSEConfig(RCC_LSE_ON);
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
		{
			if(count_over-- == 0)
			{
				((WHT_RTC_Config_t*)config)->Clock_Source = LSI_RC_40000Hz;//防止外部无晶振或晶振异常
				WHT_RTC_BSP_Config(config);//递归一下
				return;
			}
		}
	}
	else if (config->Clock_Source == LSI_RC_40000Hz)
	{
		RCC_LSICmd(ENABLE);
		while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
		{
		}
	}
	else if (config->Clock_Source == HSE_OSC_Div128)
	{
		RCC_HSEConfig(RCC_HSE_ON);
		while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
		{
		}
	}
	RCC_RTCCLKConfig(config->Clock_Source);//RTC clock source select
	RCC_RTCCLKCmd(ENABLE);

	RTC_WaitForSynchro();                      //等待RTC寄存器时钟同步
	RTC_ITConfig(RTC_IT_SEC, config->Sec_Interrupt);
	RTC_ITConfig(RTC_IT_ALR, config->Alarm_Interrupt);
	RTC_ITConfig(RTC_IT_OW, config->Over_Interrupt);

	RTC_WaitForLastTask();                     //等待RTC的寄存器操作完成
	//default 1Hz
	if (config->Clock_Source == LSE_OSC_32768Hz)
	{
		RTC_SetPrescaler(32768 - 1);
	}
	else if (config->Clock_Source == LSI_RC_40000Hz)
	{
		RTC_SetPrescaler(40000 - 1);
	}
	else if (config->Clock_Source == HSE_OSC_Div128)
	{
		RTC_SetPrescaler(config->HSE_OSC_Hz / 128 - 1);
	}
	RTC_WaitForLastTask();                     //等待RTC的寄存器操作完成

	PWR_BackupAccessCmd(DISABLE);              //close RTC & BKP registers write mode
}
/*RTC获取运行状态*/
static WHT_RTC_State_enum WHT_RTC_BSP_Get_State(const WHT_RTC_Config_t* config)
{
#define RTCEN_Bit           (0x01<<15)
	unsigned int temp;

	/**********通过BDCR寄存器的RTC时钟使能/RTC时钟源判断是否上次配置过*************/
	temp = RCC->BDCR;
	if ((temp & RTCEN_Bit) == RESET)                        //RTC En bit
		return RTC_Running_Stop;
	if ((temp & HSE_OSC_Div128) != config->Clock_Source)//RTC clock source
		return RTC_Running_Stop;

	/*******是否内部时钟提供RTC********/
	if (config->Clock_Source == LSI_RC_40000Hz)
	{
		RCC_LSICmd(ENABLE);
		while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
		{
		}
	}
	else if (config->Clock_Source == HSE_OSC_Div128)
	{
		RCC_HSEConfig(RCC_HSE_ON);
		while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
		{
		}
	}
	/****重设RTC相关配置***/
	if ((config->Alarm_Interrupt == ENABLE) || (config->Over_Interrupt == ENABLE) || (config->Sec_Interrupt == ENABLE))
		NVIC_Configuration();
	RTC_Data.Over_Callback = config->Over_Interrupt == ENABLE ? config->Over_Callback : NULL;
	RTC_Data.Alarm_Callback = config->Alarm_Interrupt == ENABLE ? config->Alarm_Callback : NULL;
	RTC_Data.Sec_Callback = config->Sec_Interrupt == ENABLE ? config->Sec_Callback : NULL;
	RTC_WaitForSynchro();                      //等待RTC寄存器时钟同步
	RTC_ITConfig(RTC_IT_SEC, config->Sec_Interrupt);
	RTC_ITConfig(RTC_IT_ALR, config->Alarm_Interrupt);
	RTC_ITConfig(RTC_IT_OW, config->Over_Interrupt);
	return RTC_Running_Well;
}
/*RTC获取时钟源*/
static WHT_RTC_Clk_enum WHT_RTC_BSP_Get_Clock_Source(void)
{
	return (WHT_RTC_Clk_enum)(RCC->BDCR & HSE_OSC_Div128);
}
/*RTC设置新时间并启动*/
static void WHT_RTC_BSP_Set_Start_Time(unsigned int time)
{
	PWR_BackupAccessCmd(ENABLE);    //open RTC & BKP registers write mode
	RTC_WaitForLastTask();          //等待RTC的寄存器操作完成

	RTC_SetCounter(time);           //将时间戳写入到RTC累加计数器
	
	RTC_WaitForLastTask();          //等待RTC的寄存器操作完成
	PWR_BackupAccessCmd(DISABLE);   //close RTC& BKP registers write mode
}
/*RTC设置闹钟时间*/
static void WHT_RTC_BSP_Set_Alarm_Time(unsigned int time)
{
	PWR_BackupAccessCmd(ENABLE);    //open RTC & BKP registers write mode
	RTC_WaitForLastTask();          //等待RTC的寄存器操作完成

	RTC_SetAlarm(time);             //将时间戳写入到RTC闹钟

	RTC_WaitForLastTask();          //等待RTC的寄存器操作完成
	PWR_BackupAccessCmd(DISABLE);   //close RTC & BKP registers write mode
}
/*RTC获取当前时间*/
static unsigned int WHT_RTC_BSP_Get_New_Time(void)
{
	return RTC_GetCounter();
}


/*全局常量*/
const WHT_RTC_BSP_t WHT_RTC_BSP =
{
	.WHT_Get_Clock_Source = WHT_RTC_BSP_Get_Clock_Source,
	.WHT_Get_State        = WHT_RTC_BSP_Get_State,
	.WHT_Set_Start_Time   = WHT_RTC_BSP_Set_Start_Time,
	.WHT_Set_Alarm_Time   = WHT_RTC_BSP_Set_Alarm_Time,
	.WHT_Config           = WHT_RTC_BSP_Config,
	.WHT_Get_New_Time     = WHT_RTC_BSP_Get_New_Time,
};


/*RTC中断服务程序*/
void RTC_IRQHandler(void)
{
	if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
	{
		RTC_ClearITPendingBit(RTC_IT_SEC);     //clear RTC Second IT
		if (RTC_Data.Sec_Callback != NULL)
			RTC_Data.Sec_Callback();
	}
	if (RTC_GetITStatus(RTC_IT_ALR) != RESET)
	{
		RTC_ClearITPendingBit(RTC_IT_ALR);     //clear RTC Alarm IT
		if (RTC_Data.Alarm_Callback != NULL)
			RTC_Data.Alarm_Callback();
	}
	if (RTC_GetITStatus(RTC_IT_OW) != RESET)
	{
		RTC_ClearITPendingBit(RTC_IT_OW);     //clear RTC Over IT
		if (RTC_Data.Over_Callback != NULL)
			RTC_Data.Over_Callback();
	}
}
